package com.example.govdata.controller;

import com.example.govdata.dto.CustomData;
import com.example.govdata.dto.CustomDataItem;
import com.example.govdata.dto.Group;
import com.example.govdata.dto.User;
import com.example.govdata.repo.InitMapper;
import com.example.govdata.util.Paillier;
import com.example.govdata.util.Utils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import java.math.BigInteger;
import java.util.*;
import java.util.stream.Stream;


@Controller
@RequestMapping("/api/demo")
public class InitController {

    @Autowired
    InitMapper initMapper;

    /**
     * 队伍列表查询
     */
    @RequestMapping(value = "/grouplist",method = RequestMethod.POST)
    @ResponseBody
    public Map<String, Object> grouplist(@RequestBody Group group) {
        Map<String, Object> res = new HashMap<>();
        try {
            List<Group> groups =initMapper.getGroups(group.getGroupName(), group.getStatus());
            List<Object> groupsList = new ArrayList<>();
            for (Group group1 : groups) {
                Map<String, Object> groupMap = new LinkedHashMap<>();
                groupMap.put("groupName", group1.getGroupName());
                groupMap.put("groupId", group1.getGroupId());
                groupMap.put("status", group1.getStatus());
                groupMap.put("memberNum", group1.getMemberNum());
                groupMap.put("date", group1.getDate());
                groupMap.put("remark", group1.getRemark());
                groupMap.put("createUser", group1.getCreateUser());
                groupMap.put("memberList", group1.getMemberList());
                groupMap.put("p", group1.getP() + "");
                groupMap.put("q", group1.getQ() + "");
                groupMap.put("lambda", group1.getLambda() + "");
                groupMap.put("n", group1.getN() + "");
                groupMap.put("nsquare", group1.getNsquare() + "");
                groupMap.put("g", group1.getG() + "");
                groupMap.put("bitLength", group1.getBitLength() + "");
                groupsList.add(groupMap);
            }
            res.put("code", "0000");
            res.put("data", groupsList);
        } catch (Exception e) {
            e.printStackTrace();
            res.put("code", "0");
        }
        return res;
    }

    /**
     * 发起组队信息保存
     */
    @RequestMapping(value = "/saveGroup",method = RequestMethod.POST)
    @ResponseBody
    public Map<String, Object> saveGroup(@RequestBody Group group) {
        Map<String, Object> res = new HashMap<>();
        try {
            group.setGroupId(System.currentTimeMillis() + "");
            group.setMemberNum(group.getMemberList().size() + "");
            group.setDate(Utils.getDateTime());
            initMapper.addGroup(group);
            initMapper.addUsers(group.getMemberList(), group.getGroupId());
            group.setStatus("A");
            initMapper.updateGroupStatus(group);
            initMapper.updateUserAgreeGroupFlg(group.getCreateUser());
            res.put("code", "0000");
            res.put("data", "");
        } catch (Exception e) {
            e.printStackTrace();
            res.put("code", "0");
        }
        return res;
    }

    /**
     * 同意邀请组队服务
     */
    @RequestMapping(value = "/agreeGroup",method = RequestMethod.GET)
    @ResponseBody
    public Map<String, Object> agreeGroup(String userId, String isagree) {
        Map<String, Object> res = new HashMap<>();
        try {
            User user = initMapper.getUser(userId);
            if (user != null && isagree.equals("Y")) {
                initMapper.updateUserAgreeGroupFlg(userId);
                List<Group> groups = initMapper.getGroupsByUserId(userId);
                for (Group group : groups) {
                    Stream<User> notAgreedUsers = group.getMemberList().stream().filter(p -> p.getAgreeGroupFlag().equals("N"));
                    if (notAgreedUsers.count() == 0) {
                        group.setStatus("N");
                        initMapper.updateGroupStatus(group);
                    }
                }
            }
            res.put("code", "0000");
            res.put("data", "");
        } catch (Exception e) {
            e.printStackTrace();
            res.put("code", "0");
        }
        return res;
    }

    /**
     * 申请密钥服务
     */
    @RequestMapping(value = "/applyKey",method = RequestMethod.GET)
    @ResponseBody
    public Map<String, Object> applyKey(String groupId) {
        Map<String, Object> res = new HashMap<>();
        try {
            Group group = initMapper.getGroupById(groupId);
            if (group != null) {
                group.setStatus("S");
                initMapper.updateGroupStatus(group);
                res.put("code", "0000");
                res.put("data", "");
            } else {
                res.put("code", "0");
            }
        } catch (Exception e) {
            e.printStackTrace();
            res.put("code", "0");
        }
        return res;
    }

    /**
     * 生成密钥服务
     */
    @RequestMapping(value = "/generateKey",method = RequestMethod.GET)
    @ResponseBody
    public Map<String, Object> generateKey(String groupId) {
        Map<String, Object> res = new HashMap<>();
        try {
            Group group = initMapper.getGroupById(groupId);
            if (group != null) {
                Paillier paillier = new Paillier();
                group.setP(paillier.getP());
                group.setQ(paillier.getQ());
                group.setLambda(paillier.getLambda());
                group.setN(paillier.getN());
                group.setNsquare(paillier.getNsquare());
                group.setG(paillier.getG());
                group.setBitLength(paillier.getBitLength());
                initMapper.updateGroupKey(group);
                group.setStatus("Y");
                initMapper.updateGroupStatus(group);
                res.put("code", "0000");
                res.put("data", paillier);
            } else {
                res.put("code", "0");
            }
        } catch (Exception e) {
            e.printStackTrace();
            res.put("code", "0");
        }
        return res;
    }

    /**
     * 数据录入服务
     */
    @RequestMapping(value = "/dataEntry",method = RequestMethod.POST)
    @ResponseBody
    public Map<String, Object> dataEntry(@RequestBody CustomData customData) {
        Map<String, Object> res = new HashMap<>();
        try {
            User user = initMapper.getUser(customData.getUserId());
            Group group = initMapper.getGroupById(customData.getGroupId());
            if (group == null) {
                throw new NullPointerException("不存在该组织或该组织未申请秘钥");
            }
            customData.setDataId(System.currentTimeMillis() + "");
            Paillier paillier = new Paillier(group.getP(),group.getQ(),group.getLambda(),group.getN(),group.getNsquare(),group.getG(),group.getBitLength());
            for (CustomDataItem customDataItem : customData.getData()) {
                customDataItem.setLarcenyNum(paillier.encryption(customDataItem.getLarcenyNum()));
                customDataItem.setRobberyNum(paillier.encryption(customDataItem.getRobberyNum()));
                customDataItem.setInjuryNum(paillier.encryption(customDataItem.getInjuryNum()));
            }
            initMapper.addCustomData(customData);
            initMapper.updateUserDataEntryFlag(user.getUserId());
            Stream<User> notEnteredUsers = group.getMemberList().stream().filter(p -> p.getDataEntryFlag().equals("N"));
            if (notEnteredUsers.count() == 0) {
                group.setStatus("E");
                initMapper.updateGroupStatus(group);
            } else {
                group.setStatus("D");
                initMapper.updateGroupStatus(group);
            }
            res.put("code", "0000");
            res.put("data", "");
        } catch (Exception e) {
            e.printStackTrace();
            res.put("code", "0");
            res.put("data", "不存在该组织或该组织未申请秘钥");
        }
        return res;
    }

    /**
     * 队伍结果数据查询服务
     */
    @RequestMapping(value = "/resultQuery",method = RequestMethod.GET)
    @ResponseBody
    public Map<String, Object> resultQuery(String groupId) {
        Map<String, Object> res = new LinkedHashMap<>();
        try {
            Group group = initMapper.getGroupById(groupId);
            if (group != null) {
                Paillier paillier = new Paillier(group.getP(),group.getQ(),group.getLambda(),group.getN(),group.getNsquare(),group.getG(),group.getBitLength());
                List<CustomDataItem> customDataItems = initMapper.getCustomDataSum(groupId);
                List<CustomDataItem> customDataItemEncry = initMapper.getCustomDataSum(groupId);
                for (CustomDataItem customDataItem : customDataItems) {
                    customDataItem.setLarcenyNum(paillier.decryption(customDataItem.getLarcenyNum()));
                    customDataItem.setRobberyNum(paillier.decryption(customDataItem.getRobberyNum()));
                    customDataItem.setInjuryNum(paillier.decryption(customDataItem.getInjuryNum()));
                }
                group.setStatus("F");
                initMapper.updateGroupStatus(group);

                List<Object> customDataItemEncryList = new ArrayList<>();
                for (CustomDataItem customDataItem : customDataItemEncry) {
                    Map<String, Object> customDataItemMap = new LinkedHashMap<>();
                    customDataItemMap.put("quarter",  customDataItem.getQuarter()+ "");
                    customDataItemMap.put("larcenyNum", customDataItem.getLarcenyNum() + "");
                    customDataItemMap.put("robberyNum", customDataItem.getRobberyNum() + "");
                    customDataItemMap.put("injuryNum", customDataItem.getInjuryNum() + "");
                    customDataItemEncryList.add(customDataItemMap);
                }
                res.put("code", "0000");
                res.put("data", customDataItems);
                res.put("encryData", customDataItemEncryList);
            }
        } catch (Exception e) {
            e.printStackTrace();
            res.put("code", "0");
        }
        return res;
    }

    /**
     * 同态计算服务
     */
    @RequestMapping(value = "/calc",method = RequestMethod.GET)
    @ResponseBody
    public Map<String, Object> calc(String groupId) {
        Map<String, Object> res = new HashMap<>();
        try {
            Group group = initMapper.getGroupById(groupId);
            if (group != null) {
                Paillier paillier = new Paillier(group.getP(),group.getQ(),group.getLambda(),group.getN(),group.getNsquare(),group.getG(),group.getBitLength());
                List<CustomDataItem> customDataItemTotal = new ArrayList<>();
                List<BigInteger> quarters = new ArrayList<>();
                quarters.add(new BigInteger("1"));
                quarters.add(new BigInteger("2"));
                quarters.add(new BigInteger("3"));
                quarters.add(new BigInteger("4"));
                customDataItemTotal.add(new CustomDataItem(quarters.get(0)));
                customDataItemTotal.add(new CustomDataItem(quarters.get(1)));
                customDataItemTotal.add(new CustomDataItem(quarters.get(2)));
                customDataItemTotal.add(new CustomDataItem(quarters.get(3)));
                List<CustomDataItem> customDataItems = initMapper.getCustomDataItem(groupId);
                for (CustomDataItem customDataItem : customDataItems) {
                    if (customDataItem.getQuarter().compareTo(customDataItemTotal.get(0).getQuarter()) == 0) {
                        customDataItemTotal.get(0).setLarcenyNum(paillier.cipher_add(customDataItemTotal.get(0).getLarcenyNum(), customDataItem.getLarcenyNum()));
                        customDataItemTotal.get(0).setRobberyNum(paillier.cipher_add(customDataItemTotal.get(0).getRobberyNum(), customDataItem.getRobberyNum()));
                        customDataItemTotal.get(0).setInjuryNum(paillier.cipher_add(customDataItemTotal.get(0).getInjuryNum(), customDataItem.getInjuryNum()));
                    } else if (customDataItem.getQuarter().compareTo(customDataItemTotal.get(1).getQuarter()) == 0) {
                        customDataItemTotal.get(1).setLarcenyNum(paillier.cipher_add(customDataItemTotal.get(1).getLarcenyNum(), customDataItem.getLarcenyNum()));
                        customDataItemTotal.get(1).setRobberyNum(paillier.cipher_add(customDataItemTotal.get(1).getRobberyNum(), customDataItem.getRobberyNum()));
                        customDataItemTotal.get(1).setInjuryNum(paillier.cipher_add(customDataItemTotal.get(1).getInjuryNum(), customDataItem.getInjuryNum()));
                    } else if (customDataItem.getQuarter().compareTo(customDataItemTotal.get(2).getQuarter()) == 0) {
                        customDataItemTotal.get(2).setLarcenyNum(paillier.cipher_add(customDataItemTotal.get(2).getLarcenyNum(), customDataItem.getLarcenyNum()));
                        customDataItemTotal.get(2).setRobberyNum(paillier.cipher_add(customDataItemTotal.get(2).getRobberyNum(), customDataItem.getRobberyNum()));
                        customDataItemTotal.get(2).setInjuryNum(paillier.cipher_add(customDataItemTotal.get(2).getInjuryNum(), customDataItem.getInjuryNum()));
                    } else if (customDataItem.getQuarter().compareTo(customDataItemTotal.get(3).getQuarter()) == 0) {
                        customDataItemTotal.get(3).setLarcenyNum(paillier.cipher_add(customDataItemTotal.get(3).getLarcenyNum(), customDataItem.getLarcenyNum()));
                        customDataItemTotal.get(3).setRobberyNum(paillier.cipher_add(customDataItemTotal.get(3).getRobberyNum(), customDataItem.getRobberyNum()));
                        customDataItemTotal.get(3).setInjuryNum(paillier.cipher_add(customDataItemTotal.get(3).getInjuryNum(), customDataItem.getInjuryNum()));
                    }
                }
                initMapper.deleteCustomDataSum(groupId);
                initMapper.addCustomDataSum(customDataItemTotal,groupId);
                group.setStatus("E");
                initMapper.updateGroupStatus(group);
                res.put("code", "0000");
                res.put("data", customDataItemTotal);
            }
        } catch (Exception e) {
            e.printStackTrace();
            res.put("code", "0");
        }
        return res;
    }
}
